﻿using NDF.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using UA.Data;
using UA.Data.Model;

namespace UA.Framework.Authorization
{
    public class UAIdentity : IIdentity
    {
        private UserAccessor userAccessor;
        private UserRoleAccessor userRoleAccessor;
        private User _user;
        private Guid? _userKey;
        private int? _userID;
        private string _userCode;


        protected UAIdentity()
        {
            this.userAccessor = new UserAccessor();
            this.userRoleAccessor = new UserRoleAccessor();
        }

        public UAIdentity(int userID) : this()
        {
            this._userID = userID;
            this.Refresh();
        }

        public UAIdentity(Guid userKey) : this()
        {
            this._userKey = userKey;
            this.Refresh();
        }

        public UAIdentity(string userCode) : this()
        {
            this._userCode = userCode;
            this.Refresh();
        }


        protected internal UserAccessor UserAccessor
        {
            get { return this.userAccessor; }
        }

        protected internal UserRoleAccessor UserRoleAccessor
        {
            get { return this.userRoleAccessor; }
        }

        public User User
        {
            get
            {
                return this._user;
            }
        }

        public void Refresh()
        {
            if (this._userKey.HasValue)
            {
                this._user = this.UserAccessor.GetByKey(this._userKey.Value);
            }
            else if (this._userID.HasValue)
            {
                this._user = this.UserAccessor.GetByID(this._userID.Value);
            }
            else
            {
                this._user = this.UserAccessor.GetByCode(this._userCode);
            }
            if (this.User != null)
            {
                this._userKey = this.User.Key;
                this._userID = this.User.ID;
                this._userCode = this.User.Code;
            }
        }



        public string AuthenticationType
        {
            get { return AuthenticationTypes.Password; }
        }

        public bool IsAuthenticated
        {
            get
            {
                return !string.IsNullOrWhiteSpace(AuthenticationType)
                    && UAPrincipal.Current != null
                    && (this.UserKey == UAPrincipal.Current.UserKey || this.UserID == UAPrincipal.Current.UserID);
            }
        }



        public int? UserID
        {
            get { return this.User == null ? this._userID : this.User.ID; }
        }

        public Guid? UserKey
        {
            get { return this.User == null ? this._userKey : this.User.Key; }
        }

        public string UserCode
        {
            get { return this.User == null ? this._userCode : this.User.Code; }
        }


        public string Name
        {
            get { return this.UserName; }
        }

        public string UserName
        {
            get { return this.User == null ? null : this.User.Name; }
        }

        public string Password
        {
            get { return this.User == null ? null : this.User.Password; }
        }



        public Role[] Roles
        {
            get { return !this.UserKey.HasValue ? null : this.UserRoleAccessor.GetRolesByUserKey(this.UserKey.Value); }
        }


        public bool HasUser
        {
            get { return this.User != null; }
        }


        public bool IsInRole(string roleName)
        {
            if (this.Roles.IsNullOrEmpty())
            {
                return false;
            }
            return this.Roles.Select(r => r.Name).Contains(roleName);
        }

        public bool IsInRoleByID(int roleID)
        {
            if (this.Roles.IsNullOrEmpty())
            {
                return false;
            }
            return this.Roles.Select(r => r.ID).Contains(roleID);
        }

        public bool IsInRoleByCode(string roleCode)
        {
            if (this.Roles.IsNullOrEmpty())
            {
                return false;
            }
            return this.Roles.Select(r => r.Code).Contains(roleCode);
        }
    }
}
